package com.mega.ycy.mixin;

import com.mega.ycy.Yiciyuan_EVENT;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.profiler.Profiler;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.WorldInfo;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.List;

@Mixin(World.class)
public abstract class WorldMixin {
    @Shadow @Final public boolean isRemote;

    @Shadow(remap = false) public boolean restoringBlockSnapshots;

    @Shadow protected abstract boolean isChunkLoaded(int x, int z, boolean allowEmpty);

    @Shadow @Final public List<EntityPlayer> playerEntities;

    @Shadow public abstract void updateAllPlayersSleepingFlag();

    @Shadow public abstract Chunk getChunkFromChunkCoords(int chunkX, int chunkZ);

    @Shadow @Final public List<Entity> loadedEntityList;

    @Shadow protected List<IWorldEventListener> eventListeners;

    @Inject(method = "<init>", at = @At("RETURN"))
    public void init(ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn, boolean client, CallbackInfo ci) {
        Yiciyuan_EVENT.LOADED_WORLDS.add((World)(Object) this);
    }

    @Overwrite
    public boolean spawnEntity(Entity entityIn)
    {
        if (Yiciyuan_EVENT.isDeath(entityIn))
            return false;
        // do not drop any items while restoring blocksnapshots. Prevents dupes
        if (!this.isRemote && (entityIn == null || (entityIn instanceof net.minecraft.entity.item.EntityItem && this.restoringBlockSnapshots))) return false;

        int i = MathHelper.floor(entityIn.posX / 16.0D);
        int j = MathHelper.floor(entityIn.posZ / 16.0D);
        boolean flag = entityIn.forceSpawn;

        if (entityIn instanceof EntityPlayer)
        {
            flag = true;
        }

        if (!flag && !this.isChunkLoaded(i, j, false))
        {
            return false;
        }
        else
        {
            if (entityIn instanceof EntityPlayer)
            {
                EntityPlayer entityplayer = (EntityPlayer)entityIn;
                this.playerEntities.add(entityplayer);
                this.updateAllPlayersSleepingFlag();
            }

            if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(entityIn, (World) (Object)this)) && !flag) return false;

            this.getChunkFromChunkCoords(i, j).addEntity(entityIn);
            this.loadedEntityList.add(entityIn);
            this.onEntityAdded(entityIn);
            return true;
        }
    }

    @Overwrite
    public void onEntityAdded(Entity entityIn)
    {
        if (Yiciyuan_EVENT.isDeath(entityIn))
            return;
        for (int i = 0; i < this.eventListeners.size(); ++i)
        {
            this.eventListeners.get(i).onEntityAdded(entityIn);
        }
        entityIn.onAddedToWorld();
    }

    @Overwrite
    public void onEntityRemoved(Entity entityIn)
    {
        if (Yiciyuan_EVENT.isSafe(entityIn))
            return;
        for (int i = 0; i < this.eventListeners.size(); ++i)
        {
            ((IWorldEventListener)this.eventListeners.get(i)).onEntityRemoved(entityIn);
        }
        entityIn.onRemovedFromWorld();
    }

    @Overwrite
    public void removeEntity(Entity entityIn)
    {
        if (Yiciyuan_EVENT.isSafe(entityIn))
            return;
        if (entityIn.isBeingRidden())
        {
            entityIn.removePassengers();
        }

        if (entityIn.isRiding())
        {
            entityIn.dismountRidingEntity();
        }

        entityIn.setDead();

        if (entityIn instanceof EntityPlayer)
        {
            this.playerEntities.remove(entityIn);
            this.updateAllPlayersSleepingFlag();
            this.onEntityRemoved(entityIn);
        }
    }

    @Overwrite
    public void removeEntityDangerously(Entity entityIn)
    {
        if (Yiciyuan_EVENT.isSafe(entityIn))
            return;
        entityIn.setDropItemsWhenDead(false);
        entityIn.setDead();

        if (entityIn instanceof EntityPlayer)
        {
            this.playerEntities.remove(entityIn);
            this.updateAllPlayersSleepingFlag();
        }

        int i = entityIn.chunkCoordX;
        int j = entityIn.chunkCoordZ;

        if (entityIn.addedToChunk && this.isChunkLoaded(i, j, true))
        {
            this.getChunkFromChunkCoords(i, j).removeEntity(entityIn);
        }

        this.loadedEntityList.remove(entityIn);
        this.onEntityRemoved(entityIn);
    }
}
